//file: libs/libc/include/arpa/ip_addr.h
//autor: jiangxinpeng
//time: 2021.12.23
//copyright: (C) 2020-2050 by jiangxinpeng,All right are reserved.

#ifndef _LIBC_IP_ADDR_H
    #define _LIBC_IP_ADDR_H

    #ifdef __cplusplus
    extern "C"
    {
    #endif

    #include <endian.h>
    #include "inet.h"

        typedef struct ip_addr
        {
            u32_t addr;
        } ip_addr_t;

        typedef struct ip_addr ip_addr_t;

        extern const ip_addr_t ip_addr_any;
        extern const ip_addr_t ip_addr_broadcast;

    //used as a fixed IP address
    #define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any)
    #define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast)

    #define IPADDR_NONE ((u32_t)0xffffffffUL)
    #define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
    #define IPADDR_ANY ((u32_t)0x00000000UL)
    #define IPADDR_BROADCAST ((u32_t)0xffffffffUL)

    #define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
    #define IP_CLASSA_NET 0xff000000
    #define IP_CLASSA_NSHIFT 24
    #define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET)
    #define IP_CLASSA_MAX 128

    #define IP_CLASSB(b) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000)
    #define IP_CLASSB_NET 0xffff0000
    #define IP_CLASSB_NSHIFT 16
    #define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET)
    #define IP_CLASSB_MAX 65536

    #define IP_CLASSC(c) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000)
    #define IP_CLASSC_NET 0xffffff00
    #define IP_CLASSC_NSHIFT 8
    #define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET)

    #define IP_CLASSD(a) ((((u32_t)(a)&0xf0000000UL) == 0xf0000000))
    #define IP_CLASSD_NET 0xffffff00
    #define IP_CLASSD_NSHIFT 28
    #define IP_CLASSD_HOST 0x0fffffff
    #define IP_MULTICAST(a) IP_CLASSD(a)

    #define IP_EXPERIMENTAL(a) (((u32_t)(a)&0xf0000000UL) == 0xf0000000)
    #define IP_BADCLASS(a) (((u32_t)(a)&0xf0000000UL) == 0xf0000000)

    #define IP_LOOPBACKNET 127

    #if BYTE_ORDER == BIG_ENDIAN
    //big endian
    #define IP4_ADDR(ipaddr, a, b, c, d)             \
        (ipaddr)->addr = ((u32_t)((a)&0xff) << 24) | \
                        ((u32_t)((b)&0xff) << 16) | \
                        ((u32_t)((c)&0xff) << 8) |  \
                        (u32_t)((d)&0xff)

    #else
    //little endian
    #define IP_ADDR(ipaddr, a, b, c, d) \
        (ipaddr)->addr = ((u32_t)((d)&0xff) << 24) | ((u32_t)((c)&0xff) << 16)((u32_t)((b)&0xff) << 8)(u32_t)((a)&0xff)
    #endif

    #define ip_addr_copy(dest, src) ((dest).addr = (src).addr)
    #define ip_addr_set(dest, src) ((dest).addr = (!(src) ? 0 : (src).addr))
    #define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
    #define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY)
    #define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = htonl(IPADDR_LOOPBACk))
    #define ip_addr_set_hton(dest, src) ((dest)->addr = (!(src) ? 0 : htonl((src)->addr)))
    #define ip_addr_set_u32(dest, src) ((dest)->addr = (src))
    #define ip_addr_get_u32(src) ((src)->addr)
    #define ip_addr_get_network(targe, host, netmask) ((targe)->addr = ((host)->addr) & ((netmask)->addr))
    //ipv4 only: set the ip address given as u32_t
    #define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
    //ipv4 only: get the ip address as u32_t
    #define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
    #define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr)

    u32_t ipaddr_addr(const char *cp);
    char *ipaddr_ntoa(const ip_addr_t *addr);
    char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buff, int bufflen);
    u32_t ipaddr_aton(const char *cp, ip_addr_t *addr);

#ifdef __cplusplus
}
#endif
#endif